package com.w08e.waai.service;

import com.w08e.waai.BinanceApiManager;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * 币安数据服务 - 优化版
 * @Author: 智能交易策略系统
 * @Date: 2025/1/14
 */
@Service
@Slf4j
public class BinanceDataService {
    
    private static final String DATA_DIR = "./binance_data";
    private static final String DEFAULT_SYMBOL = "ETHUSDT";
    private static final List<String> INTERVALS = List.of("5m", "15m", "30m", "1h", "4h", "1d");
    
    // 缓存文件生成时间，避免频繁重新生成
    private final ConcurrentHashMap<String, LocalDateTime> fileGenerationCache = new ConcurrentHashMap<>();
    
    // 5分钟缓存有效期
    private static final long CACHE_MINUTES = 5;
    
    /**
     * 获取最新24小时的K线数据（多时间框架）- 带智能缓存
     */
    public String getLatest24HourKlineData(String symbol) {
        if (symbol == null || symbol.isEmpty()) {
            symbol = DEFAULT_SYMBOL;
        }
        
        log.info("开始获取 {} 最近24小时K线数据", symbol);
        
        try {
            // 确保数据目录存在
            ensureDataDirectoryExists();
            
            // 检查是否需要重新生成数据
            if (shouldRegenerateData(symbol)) {
                generateLatestKlineData(symbol);
                // 更新缓存时间
                fileGenerationCache.put(symbol, LocalDateTime.now());
            } else {
                log.info("使用缓存的K线数据，跳过重新生成");
            }
            
            // 读取多时间框架数据
            StringBuilder dataBuilder = new StringBuilder();
            dataBuilder.append("=== ").append(symbol).append(" 最近24小时K线数据分析 ===\n\n");
            
            for (String interval : INTERVALS) {
                String intervalData = readLatestKlineData(symbol, interval);
                if (intervalData != null && !intervalData.isEmpty()) {
                    dataBuilder.append("【").append(interval).append(" 时间框架】\n");
                    dataBuilder.append(intervalData).append("\n\n");
                } else {
                    log.warn("无法获取 {} {} 时间框架数据", symbol, interval);
                }
            }
            
            String result = dataBuilder.toString();
            log.info("成功获取 {} K线数据，数据长度: {} 字符", symbol, result.length());
            return result;
            
        } catch (Exception e) {
            log.error("获取K线数据失败: {}", e.getMessage(), e);
            return "获取K线数据失败: " + e.getMessage();
        }
    }
    
    /**
     * 检查是否需要重新生成数据
     */
    private boolean shouldRegenerateData(String symbol) {
        // 检查缓存中的生成时间
        LocalDateTime lastGeneration = fileGenerationCache.get(symbol);
        if (lastGeneration != null) {
            long minutesSinceLastGeneration = ChronoUnit.MINUTES.between(lastGeneration, LocalDateTime.now());
            if (minutesSinceLastGeneration < CACHE_MINUTES) {
                log.info("距离上次生成仅{}分钟，使用缓存数据", minutesSinceLastGeneration);
                return false;
            }
        }
        
        // 检查各时间框架的数据文件是否存在且足够新
        for (String interval : INTERVALS) {
            Path filePath = findLatestDataFile(symbol, interval);
            
            if (filePath == null || !Files.exists(filePath)) {
                log.info("{}_{} 数据文件不存在，需要重新生成", symbol, interval);
                return true;
            }
            
            try {
                // 检查文件修改时间，如果超过5分钟则重新生成
                long fileAge = ChronoUnit.MINUTES.between(
                    LocalDateTime.ofInstant(Files.getLastModifiedTime(filePath).toInstant(), 
                    java.time.ZoneId.systemDefault()), 
                    LocalDateTime.now()
                );
                
                if (fileAge > CACHE_MINUTES) {
                    log.info("文件过期（{}分钟前），需要重新生成: {}", fileAge, filePath.getFileName());
                    return true;
                }
            } catch (IOException e) {
                log.warn("检查文件时间失败: {}", e.getMessage());
                return true;
            }
        }
        
        return false;
    }
    
    /**
     * 生成最新的K线数据文件 - 优化时间范围
     */
    private void generateLatestKlineData(String symbol) {
        try {
            log.info("开始生成最新K线数据文件...");
            
            LocalDateTime now = LocalDateTime.now();
            
            // 为不同时间框架获取不同范围的数据
            for (String interval : INTERVALS) {
                LocalDateTime startTime = getOptimalStartTime(interval, now);
                String startDate = startTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
                String endDate = now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
                
                log.info("获取 {} {} 数据: {} 到 {}", symbol, interval, startDate, endDate);
                
                // 调用BinanceApiManager获取数据
                BinanceApiManager.fetchAllHistorical(symbol, List.of(interval), startDate, endDate);
            }
            
            log.info("K线数据生成完成");
            
        } catch (Exception e) {
            log.error("生成K线数据失败", e);
            throw new RuntimeException("生成K线数据失败", e);
        }
    }
    
    /**
     * 根据时间框架获取最佳开始时间
     */
    private LocalDateTime getOptimalStartTime(String interval, LocalDateTime now) {
        switch (interval) {
            case "5m":
                // 5分钟数据：获取3天数据，用于超短线分析（864个数据点）
                return now.minusDays(3);
            case "15m":
                // 15分钟数据：获取5天数据，用于短线分析（480个数据点）
                return now.minusDays(5);
            case "30m":
                // 30分钟数据：获取7天数据，用于短中线分析（336个数据点）
                return now.minusDays(7);
            case "1h":
                // 1小时数据：获取14天数据，提供足够的短期趋势分析（336个数据点）
                return now.minusDays(14);
            case "4h":
                // 4小时数据：获取60天数据，用于中期趋势分析（360个数据点）
                return now.minusDays(60);
            case "1d":
                // 日线数据：获取120天数据，用于长期趋势和支撑阻力分析（120个数据点）
                return now.minusDays(120);
            default:
                return now.minusDays(7);
        }
    }
    
    /**
     * 查找最新的数据文件
     */
    private Path findLatestDataFile(String symbol, String interval) {
        try {
            Path dataPath = Paths.get(DATA_DIR);
            if (!Files.exists(dataPath)) {
                return null;
            }
            
            // 查找匹配模式的文件: SYMBOL_INTERVAL_*.csv
            String pattern = String.format("%s_%s_*.csv", symbol, interval);
            
            Path latestFile = null;
            String latestFileName = "";
            
            try (DirectoryStream<Path> stream = Files.newDirectoryStream(dataPath, pattern)) {
                for (Path file : stream) {
                    String fileName = file.getFileName().toString();
                    // 选择文件名最大的（日期最新的）
                    if (fileName.compareTo(latestFileName) > 0) {
                        latestFileName = fileName;
                        latestFile = file;
                    }
                }
            }
            
            return latestFile;
            
        } catch (IOException e) {
            log.error("查找数据文件失败: {}", e.getMessage());
            return null;
        }
    }
    
    /**
     * 读取指定时间框架的最新K线数据
     */
    private String readLatestKlineData(String symbol, String interval) {
        try {
            // 查找最新的数据文件
            Path filePath = findLatestDataFile(symbol, interval);
            
            if (filePath == null || !Files.exists(filePath)) {
                log.warn("未找到 {} {} 数据文件", symbol, interval);
                return null;
            }
            
            log.debug("读取数据文件: {}", filePath.getFileName());
            
            // 读取文件内容
            List<String> lines = Files.readAllLines(filePath);
            if (lines.isEmpty()) {
                log.warn("文件为空: {}", filePath);
                return null;
            }
            
            // 获取最近的数据行数
            int linesToTake = Math.min(calculateLinesToTake(interval), lines.size() - 1); // 减1是因为要排除表头
            
            List<String> recentLines = lines.stream()
                    .skip(Math.max(0, lines.size() - linesToTake))
                    .collect(Collectors.toList());
            
            StringBuilder result = new StringBuilder();
            result.append("时间,开盘价,最高价,最低价,收盘价,成交量,成交额,交易笔数\n");
            
            boolean isFirstLine = true;
            for (String line : recentLines) {
                if (isFirstLine && line.startsWith("open_time")) {
                    isFirstLine = false;
                    continue; // 跳过表头
                }
                
                String[] parts = line.split(",");
                if (parts.length >= 11) {
                    result.append(String.format("%s,%s,%s,%s,%s,%s,%s,%s\n",
                            parts[0], // open_time
                            parts[2], // open
                            parts[3], // high
                            parts[4], // low
                            parts[5], // close
                            parts[6], // volume
                            parts[8], // quote_volume
                            parts[9]  // trades
                    ));
                }
            }
            
            return result.toString();
            
        } catch (IOException e) {
            log.error("读取K线数据文件失败: {}", e.getMessage(), e);
            return null;
        }
    }
    
    /**
     * 根据时间框架计算需要取的行数（用于分析的最新数据点数）
     */
    private int calculateLinesToTake(String interval) {
        switch (interval) {
            case "5m": 
                // 5分钟：取最近24小时数据（288个数据点）
                return 288;
            case "15m": 
                // 15分钟：取最近24小时数据（96个数据点）
                return 96;
            case "30m": 
                // 30分钟：取最近48小时数据（96个数据点）
                return 96;
            case "1h": 
                // 1小时：取最近72小时数据（72个数据点）
                return 72;
            case "4h": 
                // 4小时：取最近30天数据（180个数据点）
                return 180;
            case "1d": 
                // 日线：取最近90天数据（90个数据点）
                return 90;
            default: 
                return 100;
        }
    }
    
    /**
     * 获取当前价格（从最新K线数据中提取）
     */
    public Double getCurrentPrice(String symbol) {
        try {
            String data = getLatest24HourKlineData(symbol);
            if (data == null || data.isEmpty()) {
                return null;
            }
            
            // 从1小时数据中提取最新收盘价
            String[] lines = data.split("\n");
            for (String line : lines) {
                if (line.contains("时间,开盘价")) {
                    // 找到表头后的下一行
                    continue;
                }
                if (line.contains(",") && !line.contains("===") && !line.contains("【")) {
                    String[] parts = line.split(",");
                    if (parts.length >= 5) {
                        return Double.parseDouble(parts[4]); // 收盘价
                    }
                }
            }
            
        } catch (Exception e) {
            log.error("获取当前价格失败", e);
        }
        return null;
    }
    
    /**
     * 每天凌晨2点清理7天前的历史数据
     */
    @Scheduled(cron = "0 0 2 * * ?")
    public void cleanupHistoricalData() {
        log.info("开始清理历史K线数据文件...");
        
        try {
            Path dataPath = Paths.get(DATA_DIR);
            if (!Files.exists(dataPath)) {
                return;
            }
            
            LocalDateTime cutoffDate = LocalDateTime.now().minusDays(7);
            String cutoffDateStr = cutoffDate.format(DateTimeFormatter.ofPattern("yyyyMMdd"));
            
            int deletedCount = 0;
            
            try (DirectoryStream<Path> stream = Files.newDirectoryStream(dataPath, "*.csv")) {
                for (Path file : stream) {
                    String fileName = file.getFileName().toString();
                    
                    // 提取文件中的日期（格式：SYMBOL_INTERVAL_YYYYMMDD_YYYYMMDD.csv）
                    String[] parts = fileName.split("_");
                    if (parts.length >= 4) {
                        String fileDateStr = parts[2]; // 第三部分是开始日期
                        
                        if (fileDateStr.compareTo(cutoffDateStr) < 0) {
                            Files.delete(file);
                            deletedCount++;
                            log.debug("删除历史文件: {}", fileName);
                        }
                    }
                }
            }
            
            log.info("历史数据清理完成，删除了 {} 个文件", deletedCount);
            
        } catch (IOException e) {
            log.error("清理历史数据失败", e);
        }
    }
    
    /**
     * 手动清理所有数据文件（测试用）
     */
    public void manualCleanupAllData() {
        log.info("手动清理所有K线数据文件...");
        
        try {
            Path dataPath = Paths.get(DATA_DIR);
            if (!Files.exists(dataPath)) {
                return;
            }
            
            int deletedCount = 0;
            
            try (DirectoryStream<Path> stream = Files.newDirectoryStream(dataPath, "*.csv")) {
                for (Path file : stream) {
                    Files.delete(file);
                    deletedCount++;
                    log.debug("删除文件: {}", file.getFileName());
                }
            }
            
            // 清空缓存
            fileGenerationCache.clear();
            
            log.info("手动清理完成，删除了 {} 个文件", deletedCount);
            
        } catch (IOException e) {
            log.error("手动清理数据失败", e);
        }
    }
    
    /**
     * 检查数据目录是否存在，不存在则创建
     */
    private void ensureDataDirectoryExists() {
        try {
            Path dataPath = Paths.get(DATA_DIR);
            if (!Files.exists(dataPath)) {
                Files.createDirectories(dataPath);
                log.info("创建数据目录: {}", DATA_DIR);
            }
        } catch (IOException e) {
            log.error("创建数据目录失败", e);
            throw new RuntimeException("创建数据目录失败", e);
        }
    }
    
    /**
     * 获取缓存状态信息
     */
    public String getCacheStatus() {
        StringBuilder status = new StringBuilder();
        status.append("=== 缓存状态 ===\n");
        
        if (fileGenerationCache.isEmpty()) {
            status.append("无缓存记录\n");
        } else {
            fileGenerationCache.forEach((symbol, time) -> {
                long minutesAgo = ChronoUnit.MINUTES.between(time, LocalDateTime.now());
                status.append(String.format("%s: %d分钟前生成\n", symbol, minutesAgo));
            });
        }
        
        return status.toString();
    }
} 